#pragma once

#include "funpl.h"
#include "ast_statements.h"
#include "operators.h"
#include <vector>

namespace funpl
{

namespace ast
{

/// Identifier node.
struct identifier : public expression
{
	util::const_char_range name;

	/// Constructor.
	identifier(node *parent = nullptr,
		const util::const_char_range &name = util::empty_const_char_range())
			: expression(node_type::identifier, parent),
			name(name) { }
};

/// Operator node.
struct unary_operator : public expression
{
	operator_id::t id;

	expression *operand;

	/// Constructor.
	unary_operator(node *parent = nullptr,
		operator_id::t id = operator_id::none)
			: expression(node_type::unary_operator, parent),
			id(id),
			operand() { }
};

/// Operator node.
struct binary_operator : public expression
{
	operator_id::t id;

	expression *left;
	expression *right;

	/// Constructor.
	binary_operator(node *parent = nullptr,
		operator_id::t id = operator_id::none)
			: expression(node_type::binary_operator, parent),
			id(id),
			left(),
			right() { }
};

struct type;

/// Cast node.
struct type_cast : public expression
{
	expression *operand;
	type *to;

	/// Constructor.
	type_cast(node *parent = nullptr)
			: expression(node_type::type_cast, parent),
			operand(),
			to() { }
};

/// Function arguments.
struct arguments : public node
{
	typedef std::vector<expression*> argument_vector;
	argument_vector args;

	/// Constructor.
	arguments(node *parent = nullptr)
			: node(node_type::arguments, parent) { }
};

/// Evaluation node.
struct evaluate : public expression
{
	expression *operand;

	arguments *args;

	/// Constructor.
	evaluate(node *parent = nullptr)
			: expression(node_type::evaluate, parent),
			operand() { }
};

struct metaarguments;

/// Template evaluation node.
struct metaevaluate : public expression
{
	expression *operand;

	metaarguments *arguments;

	/// Constructor.
	metaevaluate(node *parent = nullptr)
			: expression(node_type::metaevaluate, parent),
			operand() { }
};

struct type;

/// Type expression node.
struct type_expression : public expression
{
	type *type;

	/// Constructor.
	type_expression(node *parent = nullptr)
			: expression(node_type::type_expression, parent),
			type() { }
};

struct function;

/// Function expression node.
struct function_expression : public expression
{
	function *function;

	/// Constructor.
	function_expression(node *parent = nullptr)
			: expression(node_type::function_expression, parent),
			function() { }
};

} // namespace

} // namespace